﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Collections;

namespace UMLTouch.Core.Entities
{
    public class Intersection : IEngineEntity, IEquatable<Intersection>
    {
        double MaxDist = 20;

        #region Fields

        Point _intersectionPoint;
        List<SegmentIntersection> _segments;

        #endregion

        #region Properties

        public List<SegmentIntersection> Segments
        {
            get { return _segments; }
            set { _segments = value; }
        }
        public Point IntersectionPoint
        {
            get { return _intersectionPoint; }
            set { _intersectionPoint = value; }
        }
        public IEnumerable<Double> Angles
        {
            get
            {
                List<Double> ret = new List<double>();

                for (int i = 0; i < _segments.Count; i++)
                {
                    SegmentIntersection segment1 = _segments[i];
                    for (int j = i+1; j < _segments.Count; j++)
                    {
                        SegmentIntersection segment2 = _segments[j];
                        double val = Math.Abs(AngleBetween(segment1, segment2));
                        ret.Add(val);
                    }
                }
                return ret;
            }
        }

        #endregion

        #region Constructors

        public Intersection()
        {
            _segments = new List<SegmentIntersection>();
        }

        public Intersection(Intersection intersection)
            : this()
        {
            foreach (SegmentIntersection segment in intersection._segments)
            {
                this.AddSegment(segment.Segment, segment.IntersectionType);
            }
        }

        #endregion

        #region Methods

        public void AddSegment(Segment seg, IntersectionType type)
        {
            _segments.Add(
                new SegmentIntersection()
                {
                    IntersectionType = type,
                    Segment = seg
                }
            );
        }

        public IntersectionType Intersects(Segment segment)
        {
            IntersectionType ret = IntersectionType.NoIntersection;


            if ((IntersectionPoint - segment.StartPoint).Length < MaxDist)
            {
                ret = IntersectionType.StartIntersection;
            }
            else if ((IntersectionPoint - segment.EndPoint).Length < MaxDist)
            {
                ret = IntersectionType.EndIntersection;
            }
            return ret;
        }

        public Boolean Intersects(Intersection intersection)
        {
            return !Equals(intersection) && _segments.Intersect(intersection._segments).Count() > 0;
        }

        public bool Equals(Intersection other)
        {
            return ((_intersectionPoint - other._intersectionPoint).Length <= MaxDist);
        }

        public void Concat(Intersection other)
        {
            if (Equals(other))
            {
                _segments.AddRange(other.Segments.Except(_segments));
            }
            else
            {
                throw new Exception("The intersection points are not equals");
            }
        }

        protected double AngleBetween(SegmentIntersection segment1, SegmentIntersection segment2)
        {

            Vector v1 = GetIntersectionVector(segment1);
            Vector v2 = GetIntersectionVector(segment2);

            double ret = Vector.AngleBetween(v1, v2);

            if (segment1.IntersectionType == IntersectionType.MiddleIntersection)
            {
                v1 = segment1.Segment.ToNegateVector();
                double tmp = Vector.AngleBetween(v1, v2);
                if (tmp < ret)
                {
                    ret = tmp;
                }
            }
            else if (segment2.IntersectionType == IntersectionType.MiddleIntersection)
            {
                v2 = segment2.Segment.ToNegateVector();
                double tmp = Vector.AngleBetween(v1, v2);
                if (tmp < ret)
                {
                    ret = tmp;
                }
            }

            return ret;
        }

        protected Vector GetIntersectionVector(SegmentIntersection segment)
        {
            switch (segment.IntersectionType)
            {
                case IntersectionType.NoIntersection:
                    return new Vector();
                    break;
                case IntersectionType.MiddleIntersection:
                    return segment.Segment.ToVector();
                    break;
                case IntersectionType.StartIntersection:
                    return segment.Segment.ToVector();
                    break;
                case IntersectionType.EndIntersection:
                    return segment.Segment.ToNegateVector();
                    break;
                default:
                    return new Vector();
            }
        }



        #endregion


    }

    public enum IntersectionType
    {
        NoIntersection,
        MiddleIntersection,
        StartIntersection,
        EndIntersection
    }


}
